#pragma once

#include <functional>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <sys/epoll.h> 
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <cstdint>
#include <cstdio>
#include <atomic>

class CameraSource
{
    struct CamFrame_t {
    void *start;
        size_t length;
    };

    struct CamSource_t {
        int32_t fd;
        uint32_t bufcnt;
        enum v4l2_buf_type type;
        struct CamFrame_t *buf;
    };

    // typedef void (*CallBack)(uint8_t *buf, uint32_t len);
    // std::function<void(uint8_t *, uint32_t)> CallBack;

public:
    CameraSource() {};
    ~CameraSource() {};

    void Init() {
        CameraSourceInit("/dev/video0", 5, 1920, 1080, V4L2_PIX_FMT_UYVY);
    }
    void DeInit() {
        CameraSourceDeinit();
    }

    void RecvFrame(std::function<void(uint8_t *, uint32_t)> callback) {
        CameraFrameToBufCallBack(callback);
    }

private:
    int CameraSourceInit(const char *device, uint32_t bufcnt, uint32_t width, uint32_t height, uint32_t fmt);
    int CameraSourceDeinit(void);

    int CameraSourceGetFrame(void);
    int CameraSourcePutFrame(int32_t idx);
    int CameraFrameToBuf(int32_t idx, uint8_t *buf, uint32_t len);

    int CameraFrameToBufCallBack(std::function<void(uint8_t *, uint32_t)> callback);

private:
    struct CamSource_t m_camSource;
    const int FMT_NUM_PLANES{1};

    std::atomic_bool m_initFlag{false};
    std::atomic_bool m_runCallBackFlag{false};
};
